% RulangBridge - ruby erlang bridge
% Copyright (C) 2007-2008 tosik

% This program is free software; you can redistribute it and/or
% modify it under the terms of the GNU General Public License
% as published by the Free Software Foundation; either version 2
% of the License, or (at your option) any later version.

% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.

% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

%% rulang bridge
%% version 1.0.0.1 2007-05-16

-module(rulang).
-export([start_server/1, stop_server/1, loop/1, handle_connection/1]).

% コマンド受信用のサーバを起動する
start_server(Port) ->
	{ok, ListenSocket} = gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}]),
	io:format("[Start Rulang Server]~n"),
	spawn(rulang, loop, [ListenSocket]).

% サーバを停止する
stop_server(Pid) ->
	Ret = erlang:process_info(Pid),
	exit(Pid, suckage),
	if
		Ret == undefined ->
			io:format("[Error stopping Rulang Server]~nNot Found Process \"~w\"", [Pid]);
		true ->
			io:format("[Stop Rulang Server]")
	end.

% 受信ループのプロセス
loop(ListenSocket) ->
	{ok, Socket} = gen_tcp:accept(ListenSocket),
	spawn_link(rulang, handle_connection, [Socket]),
	loop(ListenSocket).
	
% 受信したらエントリーする
handle_connection(Socket) ->
	% エラーの確認をする
	Reason = (catch communication(Socket)),
	gen_tcp:send(Socket, io_lib:format("Error: ~w~n", [Reason])),
	ok = gen_tcp:close(Socket).

% 通信する
communication(Socket) ->
	{ok, Binary} = gen_tcp:recv(Socket, 0),
	{ok, Result} = eval(binary_to_list(Binary)),
	gen_tcp:send(Socket, io_lib:format("~p~n", [to_ruby(Result)])),
	Binary.

% コマンドを評価する
eval(Expression) ->
	{ok, Scanned, _} = erl_scan:string(Expression),
	{ok, [Parsed]} = erl_parse:parse_exprs(Scanned),
	{value, Result, _} = erl_eval:expr(Parsed, []),
	{ok, Result}.

% Ruby の文法に変換する
to_ruby(Expression) when is_list(Expression) ->
	lists:map(fun(X) -> to_ruby(X) end, Expression);
	%list_to_binary("'" ++ Expression ++ "'");
to_ruby(Expression) when is_tuple(Expression) ->
	to_ruby(tuple_to_list(Expression));
to_ruby(Expression) when is_binary(Expression) ->
	to_ruby(binary_to_list(Expression));
to_ruby(Expression) when is_integer(Expression) ->
	Expression;
to_ruby(Expression) when is_float(Expression) ->
	Expression;
to_ruby(Expression) when is_atom(Expression) ->
	atom_to_list(Expression).

